package com.waldamartin.android.mobileapplicationspairsapp.control;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

import com.google.gson.Gson;
import com.waldamartin.android.mobileapplicationspairsapp.R;
import com.waldamartin.android.mobileapplicationspairsapp.model.Game;
import com.waldamartin.android.mobileapplicationspairsapp.model.GameList;

/**
 * Class to deal with user input to select different games.
 * 
 * @author Martin
 */
public class GameListActivity extends Activity
{
	// GUI
	private ListView lvGames;
	
	// Model
	private GameList gameList; 
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_game_list);
		
		// Initialize data model on first app start or load it
		loadOrCreateDataModel();
		
		// If smartphone owner finished a game, save a few informations
		if (getIntent().hasExtra("date"))
		{
			// Get date to save
			String date = getIntent().getStringExtra("date");
			gameList.getGames().get(gameList.getLastGame()).setLastTimePlayed(date);
			
			// Check for geo information to save
			if (getIntent().hasExtra("latitude") && getIntent().hasExtra("longitude"))
			{
				gameList.getGames().get(gameList.getLastGame()).setLatitude(getIntent().getDoubleExtra("latitude", Double.NaN));
				gameList.getGames().get(gameList.getLastGame()).setLongitude(getIntent().getDoubleExtra("longitude", Double.NaN));
			}
			else if (gameList.getLastGame() != null)
			{
				gameList.getGames().get(gameList.getLastGame()).setLatitude(0);
				gameList.getGames().get(gameList.getLastGame()).setLongitude(0);
			}
			
			// Save
			SaveDataModelAsyncTask saveTask = new SaveDataModelAsyncTask();
			saveTask.execute();
		}
		
		// Setup game list
		GamesListViewAdapter listAdapter = new GamesListViewAdapter(gameList.getGames());
		lvGames = (ListView)findViewById(R.id.lvGames);
		lvGames.setAdapter(listAdapter);		
		
		// Register event handler
		registerEventHandler();
	}
	
	/**
	 * Preset some games. This function is called on first app start.
	 */
	private void initDataModelOnFirstRun()
	{
		gameList.setGames(new ArrayList<Game>());

		// Add game with name and card set
		Game newGame = new Game("Plant Pairs");
		addSet(newGame, "@drawable/ic_set_fruit_", 1, 45);		
		gameList.addGame(newGame);

		newGame = new Game("Animals Memory");
		addSet(newGame, "@drawable/ic_set_ani_", 1, 7);		
		gameList.addGame(newGame);
		
		newGame = new Game("Color Concentrate");
		addSet(newGame, "@drawable/ic_set_color_", 1, 8);		
		gameList.addGame(newGame);
		
		newGame = new Game("Eat Concentrate");
		addSet(newGame, "@drawable/ic_set_eat_", 1, 7);		
		gameList.addGame(newGame);
		
		newGame = new Game("Emotions Pairs");
		addSet(newGame, "@drawable/ic_set_emo_", 1, 9);		
		gameList.addGame(newGame);
		
		newGame = new Game("Geo Memory");
		addSet(newGame, "@drawable/ic_set_geo_", 1, 11);		
		gameList.addGame(newGame);
	}
	
	/**
	 * Function to add a set of cards and store in the data model
	 * 
	 * @param game Game name
	 * @param uriPrefix Prefix of the path and file name
	 * @param start Start index of the file name
	 * @param end End index of the file name 
	 */
	private void addSet(Game game, String uriPrefix, int start, int end)
	{
		// Add cards of set from start idex to end index
		for (Integer i = start; i <= end; i++) 
		{
			String uri = uriPrefix + String.format("%02d", i); // to load image names semi automatically
			int imgRes = GameListActivity.this.getResources().getIdentifier(uri, null, GameListActivity.this.getPackageName());

			game.addElement(imgRes);
		}
	}
	
	/**
	 * Create data model on first app start and load data model on further app starts
	 */
	private void loadOrCreateDataModel()
	{
		// Prepare fileStream and file with path
		InputStream fileInputStream = null;
		File file = new File( this.getFilesDir(), GameList.PATH );
		
		// Not first app start?
		if (file.exists())
		{
			try
			{
				// Load JSON data from file
				fileInputStream = new FileInputStream( file );
				InputStreamReader isr = new InputStreamReader(fileInputStream);
				BufferedReader bufferedReader = new BufferedReader(isr);
				StringBuilder sb = new StringBuilder();
				String line; // Read per line
				while ((line = bufferedReader.readLine()) != null) 
				{
				     sb.append(line);
				}
				
				// Parse JSON
				String jsonString = sb.toString();
				gameList = new Gson().fromJson(jsonString, GameList.class);
				fileInputStream.close();
			} 
			catch ( IOException e)
			{
				System.err.println("GameListActivity: IOException ..could not load data!");
				e.printStackTrace();
			}
		}
		else
		{
			// Create and save new model
			gameList = new GameList();
			initDataModelOnFirstRun();
			
			// Save
			SaveDataModelAsyncTask saveTask = new SaveDataModelAsyncTask();
			saveTask.execute();
		}
	}
	
	/**
	 * Register event handler
	 */
	private void registerEventHandler()
	{
		// Event handler for list entries
		lvGames.setOnItemClickListener(new LvGamesOnItemClickListener() );
	}
	
	/**
	 * Save data model changes as JSON to file
	 */
	private void saveDataModelToFile()
	{
		// Prepare OutputStream and file with path
		OutputStream fileOutputStream = null;
		File file = new File( GameListActivity.this.getFilesDir(), GameList.PATH );
		
		try
		{
			// Convert to JSON and write to file
			file.createNewFile();
			fileOutputStream = new FileOutputStream(file);
			String jsonString = new Gson().toJson(gameList);
			fileOutputStream.write( jsonString.getBytes() );
			fileOutputStream.close();
		} 
		catch (IOException e)
		{
			System.err.println("GameListActivity: IOException ..could not write data");
			e.printStackTrace();
		}
	}
	
	@Override
	protected void onPause()
	{
		super.onPause();

		// Save
		SaveDataModelAsyncTask saveTask = new SaveDataModelAsyncTask();
		saveTask.execute();
	}
	
	/**
	 * Class to save changes of data model detached from main Thread
	 * 
	 * @author Martin
	 */
	private class SaveDataModelAsyncTask extends AsyncTask<Void, Void, Void>
	{
		@Override
		protected Void doInBackground(Void... params)
		{
			// Call save routine
			saveDataModelToFile();
			return null;
		}
		
		@Override
		protected void onPostExecute(Void result)
		{
			// Debug: Show in GUI
			// Toast toast = Toast.makeText(GameListActivity.this, "..saved", Toast.LENGTH_SHORT);
			// toast.show();
		}
	}
	
	
	/**
	 * This class deals with click events for game selection
	 *
	 * @author Martin Walda
	 */
	private class LvGamesOnItemClickListener implements OnItemClickListener
	{
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,	long id)
		{
			// Prepare to change to detailed view
			
			// Remember last selected game
			gameList.setLastGame( position ); 

			// Save 
			SaveDataModelAsyncTask saveTask = new SaveDataModelAsyncTask();
			saveTask.execute();

			// Create intent
			Intent intent = new Intent(GameListActivity.this, DetailActivity.class); 

			// If available, add extra data of old game
			if (((Game)parent.getItemAtPosition(position)).getLastTimePlayed() != null)
			{
				intent.putExtra("date", ((Game)parent.getItemAtPosition(position)).getLastTimePlayed());
			}

			if ( (((Game)parent.getItemAtPosition(position)).getLatitude() != 0) && 
					(((Game)parent.getItemAtPosition(position)).getLongitude() != 0) )
			{
				intent.putExtra("latitude", ((Game)parent.getItemAtPosition(position)).getLatitude());
				intent.putExtra("longitude", ((Game)parent.getItemAtPosition(position)).getLongitude());
			}

			intent.putExtra("set", ((Game)parent.getItemAtPosition(position)).getSet());
			// intent.putExtra("set", gameList.getGames().get(position).getSet()); // Other way to get selection

			intent.putExtra("name", ((Game)parent.getItemAtPosition(position)).getName());

			startActivity(intent); 
		} // onItemClick End

	} // LvGamesOnItemClickListener End

}
